<?php

define('ROW_LENGTH', 16);


class Area
{
  private $name;
  private $initials;
  private $rows = array();
  
  public function __construct($name, $initials) {
    $this->name = $name;
    $this->initials = $initials;
  }
  
  public function add_team($team) {
    //EL CLAN ES MÁS GRANDE QUE LA FILA, LO PARTO EN LAS PARTES QUE HAGAN FALTA
    if(count($team->members) > ROW_LENGTH) {
      //los cachitos
      $chunks = array_chunk($team->members, ceil(count($team->members)/2));
      //var_dump($chunks);
      //$chunks = array_chunk($team->members, ROW_LENGTH);
      //var_dump($chunks);
      //die();
      
      $ret_ok = true;
      //vuelvo a llamar a add_team con cada uno de los cachitos
      foreach($chunks as $chunk) {
        $team_clone = clone $team;
        $team_clone->members = $chunk;
        $ret_ok = $ret_ok && $this->add_team($team_clone);
      }
      
      return $ret_ok;
    }
    
    //recorro las filas a ver si lo pudiera encajar por ahí
    foreach($this->rows as $row) {
      //¿encaja en la fila? 
      if(count($team->members) <= $row->max_space_available()) {
        //SI QUE LO HAY, los siento
        return $row->sit_users($team->members, $team->nombre);
      }
    }
    
    //no había hueco, creo otra fila
    $last_key = $this->end_key($this->rows);
    $next_key = $this->next_key($last_key);
    $this->rows[$next_key] = new Row($this->int_to_letter($next_key), $this->initials);
    
    //recursivamente llamo a add_team para que esta vez lo coloque
    return $this->add_team($team);
  }
  
  public function add_member($member) {
    //recorro las filas a ver si lo puediera encajar por ahí
    foreach($this->rows as $row) {
      //¿encaja en la fila?
      if($row->max_space_available() >= 1) {
        return $row->sit_users(array($member));
      }
    }
    
    //no había hueco, creo otra fila
    $last_key = $this->end_key($this->rows);
    $next_key = $this->next_key($last_key);
    $this->rows[$next_key] = new Row($this->int_to_letter($next_key), $this->initials);
    
    //recursivamente llamo a add_member para que esta vez lo coloque
    return $this->add_member($member);
  }
  
  private function int_to_letter($int) {
    $foo = ord('A');
    $foo += $int;
    return chr($foo);
  }
  
  private function end_key($array){
    end($array);
    return key($array);
  }
  
  private function next_key($int) {
    if(is_null($int) || !is_numeric($int)) {
      return 0;
    } else {
      $int += 1;
      return $int;
    }
  }
  
  
  public function get_html_table() {
        
    $header = array();
    $header[] = array(
      'data' => '',
    );
    for($i = 1; $i <= ROW_LENGTH; $i++) {
      $header[] = array(
        'data' => t('%n', array('%n' => $i)),
      );
    }
    
    $rows = array();
    foreach($this->rows as $row) {
      $rows[] = $row->get_row();
    }
    
    $output = array(
      'title' => $this->name,
      'table' => theme_table($header, $rows),
    );

    return $output;
  }
}



class Row
{
  private $seats;
  private $free_seats = array();
  private $row_id;
  private $area_initials;
  
  public function __construct($row_id, $area_initials) {
    $this->row_id = $row_id;
    $this->area_initials = $area_initials;
    $this->seats = $this->create_seats(0);
    $this->free_seats[] = $this->seats;
  }
  
  private function create_seats($i) {
    if($i == ROW_LENGTH) {
      return null;
    } else {
      $foo_seat = new Seat($i, $this->row_id, $this->area_initials, $this->create_seats($i + 1));
      return $foo_seat;
    }
  }
  
  public function sit_users($members, $team=null) {    
    //miro en cual de los conjuntos de asientos libres de la fila cabe el grupo
    foreach($this->free_seats as $key => $free_seat) {
      //si es el conjunto de asientos libres correcto, ubico a los integrantes
      if(count($members) <= $this->count_free_seats($free_seat)) {
        //voy sentando a criaturica por criaturica
        foreach($members as $member) {
          $free_seat->sit_user($member, $team);
          $free_seat = $free_seat->next();
        }
        
        //saco de la lista de libres el conjunto que he usado
        unset($this->free_seats[$key]);
        //si sigue habiendo huecos, lo vuelvo a meter en la lista de libres
        if(!is_null($free_seat)) {
          $this->free_seats[] = $free_seat;
        }
        
        return true;
      }
    }
    
    return false;
  }
  
  public function max_space_available() {
    $count = array();
    $count[] = 0;
    foreach($this->free_seats as $free_seat) {
      $count[] = $this->count_free_seats($free_seat);
    }
    
    return max($count);
  }
  
  public function get_row_id() {
    return $this->column_id;
  }
  
  public function get_row() {
    $rows = array();
    $rows[] = array(
      'data' => $this->row_id,
    );
    $rows = array_merge($rows, $this->seats->get_sit_row());
    return $rows;
  }

  
  private function count_free_seats($start) {
    $foo = $start;
    $count = 0;
    while(!is_null($foo) && !$foo->seat_in_use()) {
      $count += 1;
      $foo = $foo->next();
    }
    
    return $count;
  }
}


class Seat
{
  private $id;
  private $seat_number;
  private $next = null;
  private $user = null;
  private $team = null;
  
  public function __construct($id, $column_id, $area_initials, $next = null) {
    $this->id = $id;
    $this->column_id = $column_id;
    $this->area_initials = $area_initials; 
    $this->next = $next;
    
    $this->seat_number = sprintf("%s%s%02d", $area_initials, $column_id, $id);
  }
  
  public function next() {
    return $this->next;
  }
  
  public function to_string() {
    if(!is_null($this->next)) {
      $this->next->to_string();
    }
  }
  
  public function get_sit_row() {
    $rows = array();
    if(is_null($this->user)) {
      $data = '<span class="pq_asientos_free">libre</span>';
    } else {
      $user = l($this->user->name, 'user/' . $this->user->uid);
      if(!is_null($this->team)) {
        $data = t('<div class="pq_asientos_tname">%team:</div><strong>%user</strong> [%seat_id]', array('%team' => $this->team, '%user' => $user, '%seat_id' => $this->seat_number));
      } else {
        $data = t('<strong>%user</strong> [%seat_id]', array('%user' => $user, '%seat_id' => $this->seat_number));
      }
    }
    $rows[] = array(
      'data' => $data,
    );
    if(!is_null($this->next)) {
      $rows = array_merge($rows, $this->next->get_sit_row());
    }

    return $rows;
  }
  
  public function search_id($id) {
    if($this->id == $id) {
      return this;
    }
    
    if(is_null($this->next)) {
      return false;
    } else {
      return $this->next->search_id($id);
    }
  }
  
  public function sit_user($user, $team = null) {
    $this->user = $user;
    $this->team = $team;
    
    //modifico la bdd para asignar el asiento al usuario
    pq_asientos_store_seat($this->user->uid, $this->seat_number);
  }
  
  public function seat_in_use() {
    return !is_null($this->user);
  }
}